home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
013
/
resdir.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1987-01-03
|
48KB
|
1,155 lines
{$C-}
{
THE "STAYRES" code is here in a stripped-down version, without some
of its explanatory comments and without the modification history.
COMPILE with mAx and mIn both set to 300
The Hunter's Helper
Lane Ferris
4268 26th St
San Francisco,Ca. 94131
[ 70357,2716 ]
If you find this program useful, $15 would be appeciated to help in its
evolution and upkeep.
}
PROGRAM Resident_MAP;
{ * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
CONST
{ the next field is needed for the windo.inc routines }
MaxWin = 2; { Max number of windows open at one time }
Esc = #27; {character equivalent of Escape Key}
Our_Char = 113; {this is the scan code for Alt-F10}
Ctrl_Home = #119; {Control Home Scan Code }
Ctrl_End = #117; {Control End Scan Code }
Quit_Key = Ctrl_Home; {Quit and Release Memory}
Kybrd_Int = $16; {BIOS keyboard interrupt}
{------------- T Y P E D E C L A R A T I O N S ----------------------}
TYPE
Regtype = RECORD Ax, Bx, Cx, Dx, Bp, Si, Di, Ds, Es, Flags : Integer END;
HalfRegtype = RECORD Al, Ah, Bl, Bh, Cl, Ch, Dl, Dh : Byte END;
filename_type = STRING[64];
{-------------- T Y P E D C O N S T A N T S --------------------------}
CONST
{regs is defined as a typed constant to get it in the code segment}
Regs : regtype = (Ax : 0; Bx : 0; Cx : 0; Dx : 0; Bp : 0; Si : 0; Di : 0; Ds : 0; Es : 0; Flags : 0);
OurDseg : Integer = 0; {Our Data Segment Value }
OurSseg : Integer = 0; {Our Stack Segment Value }
DosSseg : Integer = 0; {Dos Stack Segment Value }
Inuse : Boolean = False; {Recursion flag }
{ The following two constants *MUST* remain in the IP:CS order }
{ because StaySave uses them as a JMP target }
DOS_IntIP : Integer = 0; {Pointer to Original IP Int value }
DOS_IntCs : Integer = 0; {Pointer to Original Cs Int value }
StackSize : Integer = 0; {Current User/or Dos Stack word size}
{-------------- V A R I A B L E S ----------------------------------------}
VAR
SaveRegs : regtype;
HalfRegs : halfregtype ABSOLUTE regs;
Terminate_flag : Boolean;
Keychr : Char;
Old_Xpos, Old_Ypos : Integer;
I : Integer;
{-----------------------------------------------------------------------------}
{ W I N D O W R O U T I N E }
{---------------------------------------------------------------------------- }
{**********************************************************************}
{ W I N D O . I N C }
{ }
{**********************************************************************}
{ Kloned and Kludged by Lane Ferris }
{ -- The Hunters Helper -- }
{ Original Copyright 1984 by Michael A. Covington }
{ Extensive Modifications by Lynn Canning 9/25/85 }
{ 9107 Grandview Dr. }
{ Overland Park, Ks. 66212 }
{ 1) Foreground and Background colors added. }
{ NOTE: Monochrome monitors are automatically set }
{ to white on black. }
{ 2) Multiple borders added. }
{ 3) TimeDelay procedure added. }
{ Requirements: IBM PC or close compatible. }
{----------------------------------------------------------------------}
{ To make a window on the screen, call the procedure }
{ MkWin(x1,y1,x2,y2,FG,BG,BD); }
{ The x and y coordinates define the window placement and are the }
{ same as the Turbo Pascal Window coordinates. }
{ The border parameters (BD) are 0 = No border }
{ 1 = Single line border }
{ 2 = Double line border }
{ The foreground (FG) and background (BG) parameters are the same }
{ values as the corresponding Turbo Pascal values. }
{ }
{ The maximum number of windows open at one time is set at five }
{ (see MaxWin=5). This may be set to greater values if necessary. }
{ }
{ After the window is made, you must write the text desired from the }
{ calling program. Note that the usable text area is actually 1 }
{ position smaller than the window coordinates to allow for the border.}
{ Hence, a window defined as 1,1,80,25 would actually be 2,2,79,24 }
{ after the border is created. When writing to the window in your }
{ calling program, the textcolor and backgroundcolor may be changed as }
{ desired by using the standard Turbo Pascal commands. }
{ }
{ To return to the previous screen or window, call the procedure }
{ RmWin; }
{ }
{ The TimeDelay procedure is involked from your calling program. It }
{ is similar to the Turbo Pascal DELAY except DELAY is based on clock }
{ speed whereas TimeDelay is based on the actual clock. This means }
{ that the delay will be the same duration on all systems no matter }
{ what the clock speed. }
{ The procedure could be used for an error condition as follows: }
{ MkWin - make an error message window }
{ Writeln - write error message to window }
{ TimeDelay(5) - leave window on screen 5 seconds }
{ RmWin - remove error window }
{ cont processing }
{----------------------------------------------------------------------}
CONST
InitDone : Boolean = False; { Initialization switch }
On = True;
Off = False;
VideoEnable = $08; { Video Signal Enable Bit }
Bright = 8; { Bright Text bit}
TYPE
Imagetype = ARRAY[1..4000] OF Char; { Screen Image in the heap }
WinDimtype = RECORD
x1, y1, x2, y2 : Integer
END;
Screens = RECORD { Save Screen Information }
Image : Imagetype; { Saved screen Image }
Dim : WinDimtype; { Saved Window Dimensions }
x, y : Integer; { Saved cursor position }
END;
VAR
Win : { Global variable package }
RECORD
Dim : WinDimtype; { Current Window Dimensions }
Depth : Integer;
{ MaxWin should be included in your program }
{ and it should be the number of windows saved }
{ at one time }
{ It should be in the const section of your program }
Stack : ARRAY[1..MaxWin] OF ^Screens;
END;
Crtmode : Byte ABSOLUTE $0040 : $0049; {Crt Mode,Mono,Color,B&W..}
Crtwidth : Byte ABSOLUTE $0040 : $004A; {Crt Mode Width, 40:80 .. }
Monobuffer : Imagetype ABSOLUTE $B000 : $0000; {Monochrome Adapter Memory}
Colorbuffer : Imagetype ABSOLUTE $B800 : $0000; {Color Adapter Memory }
CrtAdapter : Integer ABSOLUTE $0040 : $0063; { Current Display Adapter }
VideoMode : Byte ABSOLUTE $0040 : $0065; { Video Port Mode byte }
Video_Buffer : Integer; { Record the current Video}
FG : Byte; {Foregound color value }
BG : Integer; {Background color value }
BD : Integer; {Border type Value 0..2 }
Switch : Boolean;
Delta,
Xtemp, Ytemp : Integer;
x, y : Integer;
{------------------------------------------------------------------}
{ Delay for X seconds }
{------------------------------------------------------------------}
PROCEDURE TimeDelay(hold : Integer);
TYPE
RegRec = { The data to pass to DOS }
RECORD
AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags : Integer;
END;
VAR
regs : regrec;
ah, al, ch, cl, dh : Byte;
sec : STRING[2];
tmptime, result, secn, error, secn2, diff : Integer;
BEGIN
ah := $2c; {Get Time-Of-Day from DOS}
WITH regs DO {Will give back Ch:hours }
{Cl:minutes,Dh:seconds }
ax := ah SHL 8+al; {Dl:hundreds }
Intr($21, regs);
WITH regs DO
Str(dx SHR 8:2, sec); {Get seconds }
{with leading null}
IF (sec[1] = ' ') THEN
sec[1] := '0';
Val(sec, secn, error); {Conver seconds to integer}
REPEAT { stay in this loop until the time }
ah := $2c; { has expired }
WITH regs DO
ax := ah SHL 8+al;
Intr($21, regs); {Get current time-of-day}
WITH regs DO {Normalize to Char}
Str(dx SHR 8:2, sec);
IF (sec[1] = ' ') THEN
sec[1] := '0';
Val(sec, secn2, error); {Convert seconds to integer}
diff := secn2-secn; {Number of elapsed seconds}
IF diff < 0 THEN { we just went over the minute }
diff := diff+60; { so add 60 seconds }
UNTIL diff > hold; { has our time expired yet }
END; { procedure TimeDelay }
{------------------------------------------------------------------}
{ Get Absolute postion of Cursor into parameters x,y }
{------------------------------------------------------------------}
PROCEDURE Get_Abs_Cursor(VAR x, y : Integer);
VAR
Active_Page : Byte ABSOLUTE $0040 : $0062; { Current Video Page Index}
Crt_Pages : ARRAY[0..7] OF Integer ABSOLUTE $0040 : $0050;
BEGIN
X := Crt_Pages[active_page]; { Get Cursor Position }
Y := Hi(X)+1; { Y get Row }
X := Lo(X)+1; { X gets Col position }
END;
{------------------------------------------------------------------}
{ Turn the Video On/Off to avoid Read/Write snow }
{------------------------------------------------------------------}
PROCEDURE Video(Switch : Boolean);
BEGIN
IF (Switch = Off) THEN
Port[CrtAdapter+4] := (VideoMode-VideoEnable)
ELSE Port[CrtAdapter+4] := (VideoMode OR VideoEnable);
END;
{------------------------------------------------------------------}
{ InitWin Saves the Current (whole) Screen }
{------------------------------------------------------------------}
PROCEDURE InitWin;
{ Records Initial Window Dimensions }
BEGIN
IF CrtMode = 7 THEN
Video_Buffer := $B000 {Set Ptr to Monobuffer }
ELSE Video_Buffer := $B800; { or Color Buffer }
WITH Win.Dim DO
BEGIN x1 := 1; y1 := 1; x2 := crtwidth; y2 := 25 END;
Win.Depth := 0;
InitDone := True; { Show initialization Done }
END;
{------------------------------------------------------------------}
{ BoxWin Draws a Box around the current Window }
{------------------------------------------------------------------}
PROCEDURE BoxWin(x1, y1, x2, y2 : Integer; BD : Integer; FG : Byte; BG : Integer);
{ Draws a box, fills it with blanks, and makes it the current }
{ Window. Dimensions given are for the box; actual Window is }
{ one unit smaller in each direction. }
VAR
x, y, I : Integer;
TB, SID, TLC, TRC, BLC, BRC : Integer;
BEGIN
IF Crtmode = 7 THEN BEGIN
FG := 7;
BG := 0;
END;
Window(x1, y1, x2, y2);
TextColor(FG);
TextBackground(BG);
IF BD = 1 THEN BEGIN
TB := 196; {Top Border}
SID := 179; {Side Border}
TLC := 218; {Top Left Corner}
TRC := 191; {Top Right Corner}
BLC := 192; {Bottom Left Corner}
BRC := 217; {Bottom Right Corner}
END
ELSE BEGIN
TB := 205;
SID := 186;
TLC := 201;
TRC := 187;
BLC := 200;
BRC := 188;
END;
IF BD <> 0 THEN BEGIN
{ Top }
GoToXY(1, 1); { Windo Origin }
Write(Chr(TLC)); { Top Left Corner }
FOR I := 2 TO x2-x1 DO { Top Bar }
Write(Chr(TB));
Write(Chr(TRC)); { Top Right Corner
{ Sides }
FOR I := 2 TO y2-y1 DO
BEGIN
GoToXY(1, I); { Left Side Bar }
Write(Chr(SID));
GoToXY(x2-x1+1, I); { Right Side Bar }
Write(Chr(SID));
END;
{ Bottom }
GoToXY(1, y2-y1+1); { Bottom Left Corner }
Write(Chr(BLC));
FOR I := 2 TO x2-x1 DO { Bottom Bar }
Write(Chr(TB));
{ Make it the current Window }
Window(x1+1, y1+1, x2-1, y2-1);
Write(Chr(BRC)); { Bottom Right Corner }
END; {If BD <> 0} ;
GoToXY(1, 1);
TextColor(FG MOD 16); { Take Low nibble 0..15 }
TextBackground(BG); { Take High nibble 0..9 }
ClrScr;
END;
{------------------------------------------------------------------}
{ MkWin Make a Window }
{------------------------------------------------------------------}
PROCEDURE MkWin(x1, y1, x2, y2 : Integer; FG : Byte; BG : Integer; BD : Integer);
{ Create a removable Window }
BEGIN
IF (InitDone = False) THEN { Initialize if not done yet }
InitWin;
WITH Win DO Depth := Depth+1; { Increment Stack pointer }
IF Win.Depth > maxWin THEN
BEGIN
WriteLn(^G, ' Windows nested too deep ');
Halt
END;
{-------------------------------------}
{ Save contents of screen }
{-------------------------------------}
Video(Off); { Turn off Video to avoid Snow }
WITH Win DO
BEGIN
New(Stack[Depth]); { Allocate Current Screen to Heap }
IF CrtMode = 7 THEN
Stack[Depth]^.Image := monobuffer { set pointer to it }
ELSE
Stack[Depth]^.Image := colorbuffer;
END;
Video(On); { Turn the Video back on }
WITH Win DO
BEGIN { Save Screen Dimentions }
Stack[Depth]^.Dim := Dim;
Stack[Win.Depth]^.x := WhereX; { Save Cursor Position }
Stack[Win.Depth]^.y := WhereY;
END;
{ Validate the Window Placement}
IF (X2 > 80) THEN { If off right of screen }
BEGIN
Delta := (X2-80); { Overflow off right margin }
X1 := X1-Delta; { Move Left window edge }
X2 := X2-Delta; { Move Right edge on 80 }
END;
IF (Y2 > 25) THEN { If off bottom screen }
BEGIN
Delta := Y2-25; { Overflow off right margin }
Y1 := Y1-Delta; { Move Top edge up }
Y2 := Y2-Delta; { Move Bottom 24 }
END;
{ Create the Window New window }
BoxWin(x1, y1, x2, y2, BD, FG, BG);
Win.Dim.x1 := x1+1;
Win.Dim.y1 := y1+1; { Allow for margins }
Win.Dim.x2 := x2-1;
Win.Dim.y2 := y2-1;
END;
{------------------------------------------------------------------}
{ Remove Window }
{------------------------------------------------------------------}
{ Remove the most recently created removable Window }
{ Restore screen contents, Window Dimensions, and }
{ position of cursor. }
PROCEDURE RmWin;
VAR
Tempbyte : Byte;
BEGIN
Video(Off);
WITH Win DO
BEGIN { Restore next Screen }
IF crtmode = 7 THEN
monobuffer := Stack[Depth]^.Image
ELSE
colorbuffer := Stack[Depth]^.Image;
Dispose(Stack[Depth]); { Remove Screen from Heap }
Video(On);
WITH Win DO { Re-instate the Sub-Window }
BEGIN { Position the old cursor }
Dim := Stack[Depth]^.Dim;
Window(Dim.x1, Dim.y1, Dim.x2, Dim.y2);
GoToXY(Stack[Depth]^.x, Stack[Depth]^.y);
END;
Get_Abs_Cursor(x, y); { New Cursor Position }
Tempbyte := { Get old Cursor attributes }
Mem[Video_Buffer:((x-1+(y-1)*80)*2)+1];
TextColor(Tempbyte AND $0F); { Take Low nibble 0..15}
TextBackground(Tempbyte DIV 16); { Take High nibble 0..9 }
Depth := Depth-1
END;
END;
{------------------------------------------------------------------}
{------------------------------------------------------------------}
{-----------------------------------------------------------------------------}
{ S T A Y E X I T }
{-----------------------------------------------------------------------------}
PROCEDURE Stay_Xit;
{-----------------------------------------------------------------------------}
{ Stay_Xit Check Terminate Keys }
{ }
{ Clean up the Program ,Free the Environment block, the program segment }
{ memory and return to Dos. Programs using this routine ,must be the }
{ last program in memory, else ,a hole will be left causing Dos }
{ to go GooGoo . }
{-----------------------------------------------------------------------------}
BEGIN { Block }
Rmwin;
WriteLn('Stay-Resident program Terminating');
SaveRegs.Ax := $25 SHL 8+Kybrd_Int;
SaveRegs.Ds := DOS_IntCS;
SaveRegs.Dx := DOS_IntIP; { Reset the Keyboard interrupt addr }
MsDos(SaveRegs); { to its original value }
Saveregs.Ax := $49 SHL 8+0; { Free Allocated Block function}
Saveregs.Es := MemW[CSeg:$2C]; { Free environment block }
MsDos(Saveregs);
Saveregs.Ax := $49 SHL 8+0; { Free Allocated Block function}
Saveregs.Es := CSeg; { Free Program }
MsDos(Saveregs);
Intr($20, Regs); { Return to Dos }
END { StayXit } ;
{----------------------------------------------------------------------}
{ C a l l O r i g i n a l I n t e r r u p t }
{----------------------------------------------------------------------}
PROCEDURE CallOriginalIntr(VAR RegAx : Integer);
{Invoke the original DOS interrupt and }
BEGIN {Return the value in parameter }
INLINE(
$B4/$00/ {Mov Ah,Read function }
$9C/ {Push Flags }
$2E/$FF/$1E/DOS_IntIP/ {Call Far [DOS_IntIP] }
$C4/$BE/RegAx/ {Les Di,KeyChr[Bp] }
$AB {StosW Stuff in new KeyChr }
);
END; {CallOriginalIntr}
{----------------------------------------------------------------------}
{ K e y i n : R e a d K e a b o a r d }
{----------------------------------------------------------------------}
FUNCTION Keyin : Char; { Get a key from the Keyboard }
VAR Ch : Char; { If extended key, fold above 127 }
BEGIN {---------------------------------------}
REPEAT UNTIL KeyPressed;
Read(Kbd, Ch);
IF (Ch = Esc) AND KeyPressed THEN
BEGIN
Read(Kbd, Ch);
Ch := Char(Ord(Ch)+127);
END;
Keyin := Ch;
END; {Keyin}
{----------------------------------------------------------------------}
{ B e e p : S o u n d t h e H o r n }
{----------------------------------------------------------------------}
PROCEDURE Beep(N : Integer); {------------------------------------------}
BEGIN { This routine sounds a tone of frequency }
Sound(n); { N for approximately 100 ms }
Delay(100); {------------------------------------------}
Sound(n DIV 2);
Delay(100);
NoSound;
END {Beep} ;
{*************************************************************************}
{-------------------------------------------------------------------------}
{ THE FOLLOWING ARE THE USER INCLUDE ROUTINES }
{-------------------------------------------------------------------------}
{*************************************************************************}
procedure filedirectory;
{simple sorted file directory}
CONST
maxfiles = 128; {max number of files searched in a given directory}
TYPE
drivename = STRING[2];
filename = STRING[13];
pathname = STRING[64];
darray = RECORD
num : Integer;
arr : ARRAY[1..maxfiles] OF filename;
END;
register = RECORD
CASE Integer OF
1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
END;
dtarec = RECORD
dosnext : ARRAY[1..21] OF Byte;
attr : Byte;
ftime, fdate, flsize, fhsize : Integer;
fullname : ARRAY[1..13] OF Char;
END;
VAR
reg : register;
inpath : pathname;
dta : dtarec;
files : darray;
filnum : Integer;
lcount, olddtaseg,olddtaofs:integer;
drivenum:byte;
stop:boolean;
FUNCTION stlocase(st : filename) : filename;
{-convert a string to lowercase}
VAR i : Integer;
BEGIN
FOR i := 1 TO Length(st) DO
IF (st[i] >= 'A') AND (st[i] <= 'Z') THEN
st[i] := Chr(Ord(st[i])+32);
stlocase := st;
END; {stlocase}
procedure storedta(var dtaseg,dtaofs:integer);
{-return the old dta address}
begin
reg.ah := $2F;
MsDos(reg);
dtaseg:=reg.es;
dtaofs:=reg.bx;
end; {storedta}
PROCEDURE setdta(dtaseg,dtaofs:integer);
{-set new DTA address}
BEGIN
reg.ah := $1A;
reg.ds := dtaseg;
reg.dx := dtaofs;
MsDos(reg);
END; {setdta}
PROCEDURE getfiles(VAR files : darray; VAR inpath : pathname);
{-return the files in the files array}
VAR
name : filename;
startpath : pathname;
FUNCTION fileexists(VAR s : pathname; attr : Integer) : Boolean;
{-determine whether a file exists with the specified attribute}
BEGIN
reg.ah := $4E;
s[Length(s)+1] := #0;
reg.ds := Seg(s);
reg.dx := Ofs(s[1]);
reg.cx := attr;
MsDos(reg);
fileexists := ((reg.flags AND 1) = 0) AND ((dta.attr AND 31) = attr);
END; {fileexists}
PROCEDURE expandpath(VAR start, outpath : pathname);
{-add wildcards to path}
CONST
drivelets:string[26]='ABCDEFGHIJKLMNOPQRSTUVWXYZ';
VAR
ch : Char;
colpos:byte;
BEGIN
colpos:=pos(':',start);
if colpos=0 then
drivenum:=0
else
drivenum:=pos(upcase(start[pred(colpos)]),drivelets);
IF start = '' THEN BEGIN
outpath := '*.*';
Exit;
END;
ch := start[Length(start)];
IF (ch = '\') OR (ch = ':') THEN BEGIN
outpath := start+'*.*';
Exit;
END;
IF fileexists(start, 16) THEN BEGIN
outpath := start+'\*.*';
Exit;
END;
outpath := start;
END; {expandpath}
PROCEDURE parsedta(VAR name : filename);
{-return a name and extension from a DTA}
VAR
i : Byte;
BEGIN
i := 1;
WHILE dta.fullname[i] <> #0 DO i := i+1;
Move(dta.fullname, name[1], i-1);
name[0] := Chr(i-1);
END; {parsedta}
FUNCTION getfirst(VAR startpath : pathname;
VAR name : filename) : Boolean;
{-return true and a name if first file is found}
VAR
foundone : Boolean;
BEGIN
reg.ah := $4E;
reg.ds := Seg(startpath);
reg.dx := Ofs(startpath[1]);
reg.cx := 17;
MsDos(reg);
foundone := ((reg.flags AND 1) = 0);
IF foundone THEN
{scan the DTA for the file name and extension}
parsedta(name);
getfirst := foundone;
END; {getfirst}
FUNCTION getnext(VAR name : filename) : Boolean;
{-return true and a name if another file is found}
VAR
foundone : Boolean;
BEGIN
reg.ah := $4F;
reg.ds := Seg(dta);
reg.dx := Ofs(dta);
MsDos(reg);
foundone := ((reg.flags AND 1) = 0);
IF foundone THEN
{scan the DTA for the file name and extension}
parsedta(name);
getnext := foundone;
END; {getnext}
BEGIN
expandpath(inpath, startpath);
WITH files DO BEGIN
startpath[Length(startpath)+1] := #0;
num := 0;
IF getfirst(startpath, name) THEN
REPEAT
IF name[1] <> '.' THEN BEGIN
num := Succ(num);
arr[num] := name;
IF (dta.attr AND 16) <> 0 THEN arr[num] := arr[num]+'\';
END;
UNTIL (num = maxfiles) OR NOT(getnext(name));
END;
END; {getfiles}
PROCEDURE sortfiles(VAR files : darray; l, r : Integer);
{-sort via recursive quicksort}
VAR
i, j : Integer;
part : filename;
PROCEDURE Swap(i, j : Integer);
{-swap the two referenced data elements}
VAR
t : filename;
BEGIN
WITH files DO BEGIN
t := arr[i];
arr[i] := arr[j];
arr[j] := t;
END;
END; {swap}
BEGIN
IF l < r THEN WITH files DO BEGIN
i := l;
j := Succ(r);
{get a random partitioning element}
Swap(i, i+Random(j-i));
part := arr[i];
{swap elements until all less than partition are to left, etc}
REPEAT
REPEAT
i := Succ(i);
UNTIL (i > j) OR (arr[i] >= part);
REPEAT
j := Pred(j);
UNTIL (arr[j] <= part);
IF i < j THEN Swap(j, i);
UNTIL i >= j;
Swap(l, j);
sortfiles(files, l, Pred(j));
sortfiles(files, Succ(j), r);
END;
END; {sortfiles}
function bytesavailable(drivenum:byte):real;
begin
reg.ah:=$36;
reg.dl:=drivenum;
msdos(reg);
bytesavailable:=1.0*reg.bx*reg.ax*reg.cx;
end; {bytesavailable}
PROCEDURE checkmore(VAR j : Integer;var stop:boolean);
{-see if user wants to see more}
VAR
c : Char;
BEGIN
stop := False;
Write('....more? ');
Read(Kbd, c);
IF (c = ' ') OR (UpCase(c) = 'Y') THEN
j := 1
ELSE IF c = ^M THEN
j := j-1
ELSE
stop := True;
Write(Con, ^M); ClrEol;
END; {checkmore}
BEGIN
write('Enter directory mask: ');
readln(inpath);
storedta(olddtaseg,olddtaofs);
setdta(seg(dta),ofs(dta));
getfiles(files, inpath);
sortfiles(files, 1, files.num);
WriteLn;
lcount:=1;
filnum:=1;
stop:=false;
while (filnum<=files.num) and not(stop) do begin
Write(stlocase(files.arr[filnum]), '':(15-Length(files.arr[filnum])));
IF (filnum MOD 5) = 0 THEN begin
WriteLn;
lcount:=succ(lcount);
if lcount>=12 then checkmore(lcount,stop);
end;
filnum:=succ(filnum);
END;
IF (files.num MOD 5) <> 0 THEN WriteLn;
if not(stop) then writeln;
write('bytes available: ',bytesavailable(drivenum):0:0);
setdta(olddtaseg,olddtaofs);
END; {filedirectory}
{----------------------------------------------------------------------}
{ D E M O }
{----------------------------------------------------------------------}
PROCEDURE Demo; { Give Demonstration of Code }
VAR
Trash : Char;
attribyte,
OldAttribute : Byte;
Xcursor : Integer;
Ycursor : Integer;
BEGIN
KeyChr := #0; { Clear any residual krap }
MkWin(1, 5, 80, 20, white{Cyan}, Black, 2); { Make a Biiiiiiig window }
ClrScr; { Clear screen out }
filedirectory;
{ Make a little Window and hold for }
{ user to give us a goose..or whatever}
GoToXY(Xcursor, Ycursor);
mkwin(60,21,72,24,Cyan, Black, 2);
GoToXY(1, 1);
Write('Press a key . . .');
WHILE (NOT KeyPressed); { Pause until Key pressed }
WHILE KeyPressed DO { Get Ctrl-Home maybe }
Read(Kbd, KeyChr); { Read the users Key }
RmWin; { Remove the Window }
IF KeyChr = Quit_Key THEN { If Terminate Key then }
Stay_Xit; { remove ourself from Memory }
RmWin; { Remove the big window }
END; { Demo }
{-------------------------------------------------------------------------}
{ P R O C E S S I N T E R R U P T }
{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
PROCEDURE Process_Intr;
BEGIN
{This Inline routine will save the regs and Stack for Stay resident programs.
It restores DS and SS from the previously saved integer constants "OurDseg"
and "OurSSeg". This is important since Dos is not re-entrant and any attempt
to use Interrupt I/O services will clobber the very stack on which the
Resident Turbo program just saved its regs. Thus, on the final return, you
and Toto will end up somewhere other than Kansas and without your Ruby Reds.
}
{ author: Lane Ferris
- The Hunter's Helper -
Distributed to the Public Domain for use without profit.
Original Version 5.15.85
}
{ On entry the Stack will already contain: }
{ 1) Sp for Dos }
{ 2) Bp for Dos }
{ 3) Ip for Dos }
{ 4) Cs for Dos }
{ 5) Flags for Dos }
INLINE(
{ The following routine avoids the overhead of saving the DOS stack }
{ when the INT 16 function was not for a character request. This happens }
{ often (every four chars) as DOS checks on ^S/^Q/^C/Keypressed ad.nausea }
$9C/ {PushF Save Flags }
$80/$FC/$00/ {Cmp Ah,00 If Char request, }
$75/$11/ {Jne Skipit Not for us. }
$2E/
$FF/$1E/Dos_Intip/ {Call Far Cs:[Original$16] }
$9C/ {PushF Save Return Flags }
$80/$FC/Our_Char/ {Cmp Ah,Cs:OurChar Our Key? }
$74/$0E/ {Je GotIt enter Staysave code }
$9D/ {POPF Restore $16 flags }
$5D/$5D/ {Pop BP/PopBP Restore BP }
$CA/$02/$00/ {RetF 2 Return w/Key discard flags }
{Skipit} {Jmp to Original Dos Intr $16 }
$9D/ {PopF Restore the Flags }
$5D/$5D/ {Pop Bp/Pop Bp else Restore Bp & }
$2E/ { Jump to Original Dos Interrupt }
$FF/$2E/Dos_IntIP/ {Jmp Far Cs:[DOS_IntIp] }
{ Move the current active registers to a save place}
{GotIt}
$9D/ {Pop Saved Flags}
$FA/ {Cli Stop all interrupts }
{ Bp and Sp aready saved at Begin Stmt }
$55/ {Push Bp Save again for Regpak }
$BD/Regs/ {Mov Bp,offset REGS address savearea}
$2E/$89/$46/$00/ {CS:Mov [Bp+0],AX Save Users Registers }
$2E/$89/$5E/$02/ {Cs:Mov [Bp+2],Bx}
$2E/$89/$4E/$04/ {CS:Mov [Bp+4],CX}
$2E/$89/$56/$06/ {CS:Mov [Bp+6],DX}
$2E/$8F/$46/$08/ {Pop Cs:[Bp+8] Fetch Bp from stack }
$2E/$89/$76/$0A/ {CS:Mov [Bp+A],SI}
$2E/$89/$7E/$0C/ {CS:Mov [Bp+C],DI}
$2E/$8C/$5E/$0E/ {CS:Mov [Bp+E],DS}
$2E/$8C/$46/$10/ {CS:Mov [Bp+10],ES}
$9C/ {PUSHF put Flags on stack to retrieve }
$2E/$8F/$46/$12/ {POP Cs:[Bp+12]}
{ If Current SS := [OurSseg] or (Inuse = True), }
{ then dont overlay the previously saved stack. }
{ This program is being recursive. }
$2E/$80/$3E/Inuse/$01/ {Cmp Cs:[Inuse],1 Inuse = True ? }
$74/$62/ {Je ReCurin Yes, -J-U-M-P- }
{ Switch the SS:Sp reg pair over to ES:Si }
{ Put Turbo's Stack pointers into SS:Sp }
$2E/$8C/$16/DosSSeg/ {Mov Cs:DosSSeg,SS Save Dos Stack Segment }
$8C/$D6/ {Mov Si,SS Es gets Dos stack }
$8E/$C6/ {Mov Es,Si }
$2E/$8E/$16/OurSSeg/ {Mov SS,Cs:OurSSeg SS Gets our Stack segment }
$2E/$8E/$1E/OurDseg/ {Mov Ds,Cs:Our_Ds DS Gets our Data Segment }
{ If ES:Si (stack ptr) <> OurSSeg then }
{ Sp := Virgin Turbo Stack pointer. }
{ If Es:Si := OurSSeg, then this is a Read or }
{ Write before Inuse was set True. Dont clobber }
{ the current setting of Turbo stack pointer. }
$2E/$3B/$36/OurSSeg/ {Cmp Si,Cs:OurSSeg If SS := OurSSeg then }
$89/$E6/ {Mov Si,Sp dont clobber saved regs }
$74/$05/ {Je $+5 else get virgin stack ptr }
$3E/$8B/$36/$74/$01/ {Mov Si,Ds:[174] ..(cf. code at B2B 3.0x) }
$87/$F4/ {Xchg Sp,Si Set new Stack Pointer }
{ Stack Dos/User interrupted pgm regs for Exit. }
{ These are the original interrupt process regs }
{ that must be returned on interrupt return }
$2E/$FF/$76/$00/ {Push [Bp+0] Save Ax }
$2E/$FF/$76/$02/ {Push [Bp+2] Save Bx }
$2E/$FF/$76/$04/ {Push [Bp+4] Save Cx }
$2E/$FF/$76/$06/ {Push [Bp+6] Save Dx }
{Push [Bp+8] Save Bp }
$2E/$FF/$76/$0A/ {Push [Bp+A] Save Si }
$2E/$FF/$76/$0C/ {Push [Bp+C] Save Di }
$2E/$FF/$76/$0E/ {Push [Bp+E] Save Ds }
$2E/$FF/$76/$10/ {Push [Bp+10] Save Es }
{ Now stack the lesser of current stack size or }
{ 40 Words to our stack, to be re-stack on the }
{ interrupted pgms stack on exit. This is done }
{ to allow recursive entry into Dos/or other non }
{ re-entrant pgms. }
$29/$C9/ {Sub Cx,Cx Find minimum of current stack }
$29/$F1/ {Sub Cx,Si size or 40 words to save. }
$D1/$E9/ {Shr Cx,1 Stackbytes/2 for words. }
$83/$F9/$40/ {Cmp Cx,+40 This keeps up from overrunning }
$7E/$03/ {Jle $+3 the Stack Segment when it is less}
$B9/$40/$00/ {Mov Cx,40 than Dos stack size }
$2E/$89/$0E/StackSize/ {Mov Cs:StackSize,Cx Save current stack size }
{Restack:}
$26/$FF/$34/ {Push Es:[Si] Our Stack := Dos Es:Si }
$46/$46/ {Inc Si/Inc Si Get Next Dos Stack Word }
$E2/$F9/ {Loop to Restack }
$56/ {Push Si Save bottom of Dos Stack }
$2E/$8C/$5E/$0E/ {Mov Cs:[Bp+E],Ds Set New Data Segmt in regs}
{Recurin} { Jump here if Recursion }
$FB {Sti Enable Interrupts }
);
{ Check the Int 16 request function in Ah reg: }
{ 0 = read character from Keyboard }
{ 1 = check character available }
{ 2 = check shift key values }
IF Halfregs.Ah = Ord(Our_Char) { Separate the tests so code }
THEN IF (NOT InUse) THEN { performs efficiently. }
{ Must be OUR key and not busy }
BEGIN { Demo }
InUse := True; { "dont clobber saved stack"}
Demo;
CallOriginalIntr(Regs.Ax); { Get input key for the users }
IF HalfRegs.Ah = Ord(Our_Char) THEN Beep(650);
InUse := False; { ok to restore interrupted stack }
END; { Demo }
{Version 3.31}
{ Inline Code to restore the stack and regs moved}
{ to the Turbo Resident Stack which allows }
{ re-entrancy into Dos for I/O and recursion }
{ for Turbo Terminate & Stay Resident programs. }
{ Author: Lane Ferris }
{ - The Hunter's Helper - }
{ Distributed to the Public Domain for use without profit. }
{ Original Version 5.15.85 }
{----------------------------------------------------------------------}
{ Restore the Dos (or interrupted pgm) Regs and Stack }
{----------------------------------------------------------------------}
{ On entry the Stack will already contain: }
{ Pointer to bottom of stack }
{ Bottom of Dos Stack Ptr }
{ StackSize words of saved pgm stack }
{ Dos Flags }
{ Dos Code Segment }
{ Dos Instruction Ptr }
{ Dos Base Pointer }
{ Dos Original Stack Ptr }
{ Retrieve the Regpack registers as they were }
{ stored for the Interrupt Entry. }
INLINE(
$BD/Regs/ {Mov Bp,offset REGS}
$2E/$8B/$46/$00/ {CS:Mov Ax,[Bp+0]}
$2E/$8B/$5E/$02/ {Cs:Mov Bx,[Bp+2]}
$2E/$8B/$4E/$04/ {CS:Mov Cx,[Bp+4]}
$2E/$8B/$56/$06/ {CS:Mov Dx,[Bp+6]}
$2E/$8B/$76/$0A/ {CS:Mov Si,[Bp+A]}
$2E/$8B/$7E/$0C/ {CS:Mov Di,[Bp+C]}
$2E/$8E/$5E/$0E/ {CS:Mov DS,[Bp+E]}
$2E/$8E/$46/$10/ {CS:Mov ES,[Bp+10]}
$2E/$FF/$76/$12/ {Push Cs:[Bp+12] }
{PopF }
{ The following code was added to avoid }
{ the 80286 Pop flag (POPF) bug which }
{ enables interrupts while we are trying}
{ to POP the stack on odd byte boundry }
$EB/$01/ {JMP $+3 Skip over IRET }
$CF/ {IRET POP IP/CS/Flags }
$0E/ {PUSH CS Make a return }
$E8/$FB/$FF/ {CALL CS:$-2 Pop the Flags}
{ If [Cs:InUse]:= True, then dont restore the stack.}
{ This program is being recursive. Else restore Dos }
{ Stack and Program Entry registers for final exit. }
$2E/$80/$3E/Inuse/$01/ {Cmp byte ptr Cs:[Inuse],1 }
$74/$25/ {Je ReCurOut J-U-M-P }
{ Move "StackSize" words back to the interrupted pgms}
{ stack. The originals could have been clobber by our}
{ being recursive. (Especially true of DOS) }
$FA/ { Cli ; Stop all interrupts }
$5E/ {Pop Si Bottom of Dos Stack }
$2E/$8B/$0E/StackSize/ {Mov Cx,Cs:StackSize Saved Stack Words }
$2E/$8E/$06/DosSSeg/ {Mov ES,Cs:DosSSeg Get Dos StackSegment }
{Restack:}
$4E/$4E/ {Dec Si/Dec Si Backup Dos Stack }
$26/$8F/$04/ {Pop Es:[Si] Dos Stack := Our Stack }
$E2/$F9/ {Loop to Restack }
$89/$F5/ {Mov Bp,Si Save Dos Sp across Pops }
{ - C - A - U - T - I - O - N - }
{ Restore the original interrupted programs regs }
{ except Ax. Ax usually contains status. It contains }
{ a scan code and key for Int 16. You may want to }
{ rework this if using another interrupt. }
$07/ {Pop Es }
$1F/ {Pop Ds }
$5F/ {Pop Di }
$5E/ {Pop Si }
$5A/ {Pop Dx }
$59/ {Pop Cx }
$5B/ {Pop Bx }
$44/$44/ {Inc sp/Inc sp Thow old Ax value away }
$89/$EC/ {Mov Sp,Bp Setup Dos Stack Ptr }
$2E/$8E/$16/DosSSeg/ {Mov SS,Cs:DosSSeg Give back Dos Stack }
{RecurOut} {Clean up the Stack }
$5D/ {Pop Bp Throw away old dos Sp }
$BD/Regs/ {Mov Bp,offset REGS }
$2E/$FF/$76/$12/ {Push Cs:[Bp+12] Flags from last }
{PopF interrupt. }
{ The following code was added to avoid }
{ the 80286 Pop flag (POPF) bug which }
{ enables interrupts while we are trying }
{ to POP the stack on odd byte boundry }
$EB/$01/ {JMP $+3 Skip over IRET }
$CF/ {IRET POP IP/CS/Flags }
$0E/ {PUSH CS Make a return }
$E8/$FB/$FF/ {CALL CS:$-2 Pop the Flags}
$5D/ {Pop Bp Retrieve old BP }
$FB/ {Sti Enable interrupts }
$CA/$02/$00 {Ret Far 002 Thow old flags away}
);
END; {Process_Intr}
{-------------------------------------------------------------------------}
{ M A I N }
{-------------------------------------------------------------------------}
{ The main program installs the new interrupt routine }
{ and makes it permanently resident as the keyboard }
{ interrupt. The old keyboard interrupt is addressed }
{ through #60H, so it can still be used. }
{ }
{ The following dos calls are used: }
{ Function 25 - Install interrupt address }
{ input al = int number, }
{ ds:dx = address to install }
{ Function 35 - get interrupt address }
{ input al = int number }
{ output es:bx = address in interrupt }
{ Function 31 - terminate and stay resident }
{ input dx = size of resident program }
{ obtained from the memory }
{ allocation block at [Cs:0 - $10 + 3] }
{ Function 49 - Free Allocated Memory }
{ input Es = Block Segment to free }
{ Interrupt 20 - Return to invoking process }
{-----------------------------------------------------}
BEGIN {**main**}
InUse := False; { Turn off the Inuse flag in case we do a write}
OurDseg := DSeg; { Save the Data Segment Address for Interrupts }
OurSseg := SSeg; { Save our Stack Segment for Interrupts }
Terminate_Flag := False; { Havent received a Kill key yet }
SaveRegs.Es := 00; { Clear for Dos 3.0 bug }
{ now install the interrupt routine}
{ Initialize Your Progam Here since you wont get }
{ control again until "Our_Char" is entered from }
{ the Keyboard. }
SaveRegs.Ax := $3500+Kybrd_Int;
Intr($21, SaveRegs); {get the address of keyboard interrupt }
DOS_IntIp := SaveRegs.BX; { Location of DOS Interrupt Ip }
DOS_IntCs := SaveRegs.Es; { Location of DOS Interrupt Cs }
SaveRegs.Ax := $2500+Kybrd_Int;
SaveRegs.Ds := CSeg;
SaveRegs.Dx := Ofs(Process_Intr);
Intr($21, SaveRegs); { set the keyboard interrupt to point to
"Process-Intr" above}
WriteLn(' Turbo Stay-Resident DIR program (3.33): Press Alt-F10');
writeln(' Resident interface by Lane Ferris and Neil Rubenking');
{****************************************************************************}
{----------------------------------------------------------------------------}
{ END OF INITALIZE PROGRAM CODE }
{----------------------------------------------------------------------------}
{****************************************************************************}
{ Now terminate and stay resident }
{ The following Call utilizes the new }
{ Terminate & Stay Resident function }
{ by passing the Memory Control Block }
{ allocation size set when Turbo prolog }
{ issued Int 21/function 4A(shrink block)}
{ calculated from mInimum and mAximum op-}
{ tions menu. The MCB sits one paragraph }
{ above the PSP. }
{ Pass return code of zero }
SaveRegs.Ax := $3100; { Terminate and Stay Resident }
SaveRegs.Dx := MemW[CSeg-1:0003]; { Prog_Size from Allocation Blk}
Intr($21, SaveRegs);
{ END OF RESIDENCY CODE }
END.